/**
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
*/
package com.ubergeek42.WeechatAndroid.relay;
import android.graphics.Typeface;
import android.support.annotation.Nullable;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.Spanned;
import android.text.style.BackgroundColorSpan;
import android.text.style.CharacterStyle;
import android.text.style.ForegroundColorSpan;
import android.text.style.LeadingMarginSpan;
import android.text.style.StyleSpan;
import android.text.style.UnderlineSpan;
import com.ubergeek42.WeechatAndroid.service.P;
import com.ubergeek42.WeechatAndroid.utils.Linkify;
import com.ubergeek42.weechat.Color;
import com.ubergeek42.weechat.ColorScheme;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Date;
public class Line {
final private static Logger logger = LoggerFactory.getLogger("Buffer");
final private static boolean DEBUG = false;
// core message data
final public long pointer;
final public Date date;
final public String prefix;
final public String message;
// additional data
final public int type;
public @Nullable String speakingNick;
public boolean privmsg, action, visible, highlighted;
// sole purpose of this is to prevent onClick event on inner URLSpans to be fired
// when user long-presses on the screen and a context menu is shown
public boolean clickDisabled = false;
// processed line ready to be displayed
volatile public @Nullable Spannable spannable = null;
public Line(long pointer, Date date, String prefix, @Nullable String message,
boolean visible, boolean highlighted, @Nullable String[] tags) {
this.pointer = pointer;
this.date = date;
this.prefix = prefix;
this.message = (message == null) ? "" : message;
this.visible = visible;
this.highlighted = highlighted;
if (tags != null) {
boolean log1 = false;
boolean notifyNone = false;
for (String tag : tags) {
if (tag.equals("log1"))
log1 = true;
else if (tag.equals("notify_none"))
notifyNone = true;
else if (tag.startsWith("nick_"))
this.speakingNick = tag.substring(5);
else if (tag.endsWith("_privmsg"))
this.privmsg = true;
else if (tag.endsWith("_action"))
this.action = true;
}
if (tags.length == 0 || !log1) {
this.type = LINE_OTHER;
} else {
// Every "message" to user should have one or more of these tags
// notifyNone, notify_highlight or notify_message
this.type = notifyNone ? LINE_OWN : LINE_MESSAGE;
}
} else {
// there are no tags, it's probably an old version of weechat, so we err
// on the safe side and treat it as from human
this.type = LINE_MESSAGE;
}
if (type != LINE_MESSAGE) speakingNick = null;
}
final public static int LINE_OTHER = 0;
final public static int LINE_OWN = 1;
final public static int LINE_MESSAGE = 2;
//////////////////////////////////////////////////////////////////////////////////////////// processing stuff
public void eraseProcessedMessage() {
if (DEBUG) logger.debug("eraseProcessedMessage()");
spannable = null;
}
public void processMessageIfNeeded() {
if (DEBUG) logger.debug("processMessageIfNeeded()");
if (spannable == null) processMessage();
}
/**
* process the message and create a spannable object according to settings
* * TODO: reuse span objects (how? would that do any good?)
* * the problem is that one has to use distinct spans on the same string
* * TODO: allow variable width font (should be simple enough
*/
public void processMessage() {
if (DEBUG) logger.debug("processMessage()");
String timestamp = (P.dateFormat == null) ? null : P.dateFormat.format(date);
boolean encloseNick = P.encloseNick && privmsg && !action;
Color.parse(timestamp, prefix, message, encloseNick, highlighted, P.maxWidth, P.align);
Spannable spannable = new SpannableString(Color.cleanMessage);
if (this.type == LINE_OTHER && P.dimDownNonHumanLines) {
spannable.setSpan(new ForegroundColorSpan(ColorScheme.get().chat_inactive_buffer[0] | 0xFF000000), 0, spannable.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
} else {
CharacterStyle droidSpan;
for (Color.Span span : Color.finalSpanList) {
switch (span.type) {
case Color.Span.FGCOLOR: droidSpan = new ForegroundColorSpan(span.color | 0xFF000000); break;
case Color.Span.BGCOLOR: droidSpan = new BackgroundColorSpan(span.color | 0xFF000000); break;
case Color.Span.ITALIC: droidSpan = new StyleSpan(Typeface.ITALIC); break;
case Color.Span.BOLD: droidSpan = new StyleSpan(Typeface.BOLD); break;
case Color.Span.UNDERLINE: droidSpan = new UnderlineSpan(); break;
default: continue;
}
spannable.setSpan(droidSpan, span.start, span.end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
}
}
if (P.align != Color.ALIGN_NONE) {
LeadingMarginSpan margin_span = new LeadingMarginSpan.Standard(0, (int) (P.letterWidth * Color.margin));
spannable.setSpan(margin_span, 0, spannable.length(), Spanned.SPAN_INCLUSIVE_INCLUSIVE);
}
// what a nice little custom linkifier we've got us here
Linkify.linkify(spannable);
this.spannable = spannable;
}
// is to be run rarely—only when we need to display a notification
public String getNotificationString() {
return String.format((!privmsg || action) ? "%s %s" : "<%s> %s",
Color.stripEverything(prefix),
Color.stripEverything(message));
}
}